package fr.auzaiphe.commun.reseau;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;


/**
 * Gestionnaire d'une socket client, reception et envoie de message
 * @author Jojo
 * @author Hugo
 * @author Antho
 */
public class ReseauServeurClientHandler extends Thread
{
	private ReseauServer server;			// Reference vers le serveur du chat
	private Socket socket;				    // Socket particulière du client
	private InetAddress clientInetAdress; 	// Adresse IP du client
	private ReseauPacketHandler packetHandler;
	private ObjectInputStream streamIn;	    // Pour la reception de message
	private ObjectOutputStream streamOut;   // Pour l'envoie de message
	private boolean run;

	/**
	 * Constructeur
	 * @param pServer
	 * @param pSocket
	 */
	public ReseauServeurClientHandler(ReseauServer pServer, Socket pSocket)
	{
		super();
		this.server = pServer;
		this.socket = pSocket;
		this.clientInetAdress = this.socket.getInetAddress();
		this.run = true;
	}

	/**
	 * Envoie de message au serveur
	 * @param pMessage Contenu du message
	 */
	public void send( Packet pPaquet )
	{
		try
		{
			this.streamOut.writeObject( pPaquet );
			this.streamOut.flush();
		}
		catch (IOException e)
		{
			System.out.println(this.clientInetAdress + " ERROR sending: " + e.getMessage());
			this.server.remove(this.clientInetAdress);
			this.interrupt();
		}
	}

	/**
	 * Recoie les messages du client et les envoies au serveur
	 * Ils seront trait�s en fonction de la source
	 */
	@Override
	public void run()
	{
		System.out.println("Server Thread " + this.clientInetAdress + " running.");
		Packet paquetRecu;

		while ( this.run )
		{
			try
			{
				paquetRecu = ( Packet ) this.streamIn.readObject();
				if ( paquetRecu.getDestination() == null )
				{
					// Paquet en broadcast
					this.server.broadcast( paquetRecu );
				}
				else if ( paquetRecu.destination.equals( this.server.getServer().getInetAddress() ) )
				{
					// Paquet adresser à quelqu'un
					this.server.sendTo( paquetRecu.destination, paquetRecu );
				}
				else
				{
					// Paquet pour le serveur
					this.server.getPacketHandler().action( paquetRecu );
				}
			}
			catch (IOException ioe)
			{
				System.out.println(this.clientInetAdress + " ERROR reading: "+ ioe.getMessage());
				this.server.remove(this.clientInetAdress);
				this.interrupt();
			}
			catch (ClassNotFoundException e)
			{
				e.printStackTrace();
			}
		}
	}

	/**
	 * Interruption du thread
	 */
	@Override
	public void interrupt()
	{
		this.run = false;
	}

	/**
	 * Met en place les flux d'entree et sortie avec le client.
	 * @throws IOException
	 */
	public void open() throws IOException
	{
		this.streamIn = new ObjectInputStream( new BufferedInputStream(this.socket.getInputStream()) );
		this.streamOut = new ObjectOutputStream( new BufferedOutputStream(this.socket.getOutputStream()) );
		this.streamOut.flush(); // Le flush sert � envoyer le header pour permettre au client d'ouvrir le ObjectInputStream
	}

	/**
	 * Ferme la connexion avec le client
	 * @throws IOException
	 */
	public void close() throws IOException
	{
		if (this.socket != null) this.socket.close();
		if (this.streamIn != null) this.streamIn.close();
		if (this.streamOut != null) this.streamOut.close();
		this.interrupt();
	}

	/**
	 * Getter
	 * @return String adresse IP du client
	 */
	public InetAddress getClientInetAdress()
	{
		return this.clientInetAdress;
	}
}
